<?php
// Get an idea
// fx_control::createType('text')->binding(st_model, 'field_name')->render();
class fx_control 
{
	protected $_source = array(
		'model'	 => null,
		'source' => null,
		'option' => array(
			'display' => null,
			'value' => null
		)
	);
	
	protected $_data = array(
		'field' => null,
		'type'=> null,
		'tag' => null,
		'name'=> null,
		'id'=> null,
		'classes' => array('inputText' => 'inputText'),
		'value'	  => null,
		'options' => array(),
		'events' => array(),
		'checked' => null,
		'selected' => null
	);
	
	protected $_preDefineEvents = array(
			'onchange', 'onclick', 
			'onfocus', 'onblur',
			'onmouseover', 'onmouseout',
			'onload', 'onunload', 'onsubmit');
	
	public function __construct() 
	{
	}
	
	public static function newInstance($name = null)
	{
		$control = new fx_control();
		if (!empty($name)) {
			$control->_data['id'] = $name;
			$control->_data['name'] = $name;
		}
		return $control; 
	}
	
	public function setData($key, $value) 
	{
		$this->_data[$key] = $value;
		return $this;
	}
	
	public function getData($key = null) 
	{
		if (!empty($key)) {
			return $this->_data[$key];
		}
		return $this->_data;
	}
	
	public function removeData($key)
	{
		unset($this->_data[$key]);
		return $this;
	}
	
	public function addClass($className) 
	{
		$this->_data['classes'][$className] = $className;
		return $this;
	}
	
	public function removeClass($className) 
	{
		unset($this->_data['classes'][$className]);
		return $this;
	}
	
	public function addOption($label, $value) 
	{
		$this->_data['options'][$label] = $value;
		return $this;
	}
	
	public function removeOption($label) 
	{
		unset($this->_data['options'][$label]);
		return $this;
	}
	
	public function setDataSource($dataSource) 
	{
		if (!empty($dataSource)) {
			$this->_source = $dataSource;
		}
		else {
			throw new Exception("Data Source Must Not Null");
		}
		return $this;
	}
	
	public function getDataSource() 
	{
		return $this->_source;
	}
	
	public function setModel($model) 
	{
		$this->_source['model'] = & $model;
		return $this;
	}
	
	public function getModel() 
	{
		$model =& $this->_source['model'];
		return $model;
	}
	
	public function createType($type) 
	{
		switch ($type) {
			case 'matchedText':
				$this->_data['tag'] = 'span';
				$this->_data['type'] = $type;
				break;
			case 'label':
				$this->_data['tag'] = 'label';
				$this->_data['type'] = $type;
				break;
			case 'file':	
			case 'text':
			case 'checkbox':
			case 'radio':
			case 'password':
			case 'hidden':
				$this->_data['tag'] = 'input';
				$this->_data['type'] = $type;
				break;		
			case 'combobox':
			case 'option':	
				$this->_data['tag'] = 'select';
				$this->_data['type'] = $type;
				break;	
			case 'submit':
			case 'reset':	
			case 'button':
			case 'linkbutton':	
				$this->_data['tag'] = 'button';
				$this->_data['type'] = $type;
				break;
			case 'editor':
				$this->_data['tag'] = 'textarea';
				$this->_data['type'] = $type;
				$this->addClass('editor');
				break;
			default:
				$this->_data['tag'] = 'input';
				$this->_data['type'] = 'text';
				break;	
		}
		return $this;
	}
	
	public function binding($model, $fieldName, $source = null, $optionPath = null) 
	{
		$this->_data['id'] = $this->_data['tag'].'_'.$fieldName;
		$this->_data['field'] = $fieldName;
		if (empty($this->_data['name'])) {
			$this->_data['name'] = $fieldName;
		}
		$this->_data['value'] = $model->getData($fieldName);
		$this->setModel($model);
		if (!empty($source)) {
			$this->_source['source'] = $source;
			if (empty($optionPath)) {
				if ($this->_data['tag'] === 'select') {
					throw new Exception('Listbox Control Must Be Config Display Member, Value Member When Has Binded A Source');
				}
			} else {
				$options = explode('/', $optionPath);
				if (count($options) != 2) {
					throw new Exception('Option Path Must Be String Like "DisplayMember/ValueMember"');
				}
				$this->_source['option']['value'] = $options[0];
				$this->_source['option']['display'] = $options[1];
			}
		}
		return $this;
	}
	
	public function bindingOptionValue($value, $source = null, $optionPath = null)
	{
		$this->_data['value'] = $value;
		if (!empty($source)) {
			$this->_source['source'] = $source;
			if (empty($optionPath)) {
				if ($this->_data['tag'] === 'select') {
					throw new Exception('Listbox Control Must Be Config Display Member, Value Member When Has Binded A Source');
				}
			} else {
				$options = explode('/', $optionPath);
				if (count($options) != 2) {
					throw new Exception('Option Path Must Be String Like "DisplayMember/ValueMember"');
				}
				$this->_source['option']['value'] = $options[0];
				$this->_source['option']['display'] = $options[1];
			}
		}
		return $this;
	}
	
	public function addEvent($eventKey, $handler)
	{
		if (!in_array($event, $this->_preDefineEvents)) {
			return $this;
		}
		$this->_data['events'][$eventKey] = $handler;
		return $this;
	}
	
	public function removeEvent($eventKey)
	{
		unset($this->_data['events'][$eventKey]);
		return $this;
	}
	
	public function getEventHandler($eventKey)
	{
		if (isset($this->_data['events'][$eventKey])) {
			return $this->_data['events'][$eventKey];
		}
		return null;
	}
	
	public function value($value)
	{
		$this->_data['value'] = $value;
		return $this;
	}
	
	/*
	 * Phải tạo kiểu trước khi sử dụng phương thức này
	 * Kiểu phải là option
	 * Sử dụng khi muốn tạo ra một dropdowbox loại option
	 * không gắn kết với bất kỳ model nào mà đơn giản gắn
	 * kết với giá trị của một đối tượng
	 * index là tên phương thức lấy về giá trị của đối tượng
	 * đặc biệt sử dụng với kiểu [option] (eg: createType('option'))
	 * nếu giá trị trả về của phương thức trùng với phần tử option
	 * của control thì sẽ được chọn một cách tự động
	 * */
	public function bindingOption($object, $method) 
	{
		if ($this->_data['type'] != 'option') {
			throw new Exception("You not set type of control or type of control is not [option]");
		}
		$this->_data['value'] = $object->$method();
		return $this;
	}
	
	public function bindingCheckbox($values)
	{
		if (in_array($this->_data['value'], $values)) {
			$this->_data['checked'] = 'checked = "checked"';
		}
		return $this;
	}
	
	public function bindingValue($value)
	{
		if ($this->_data['value'] == $value) {
			$this->_data['checked'] = 'checked = "checked"';
		} 
		return $this;	
	}
	
	public function configOption($displayMember, $valueMember)
	{
		$this->_source['option']['label'] = $displayMember;
		$this->_source['option']['value'] = $valueMember;
		return $this;
	}
	
	public function render() 
	{
		$className = '';
		if ($this->_data['tag'] === 'button') {
			unset($this->_data['classes']['inputText']);	
		}
		if ($this->_data['type'] === 'file') {
			unset($this->_data['classes']['inputText']);	
		}
		if (count($this->_data['classes']) > 0) {
			$className = implode(' ', $this->_data['classes']);
		}
		$output = '<'.$this->_data['tag'];
		if ($this->_data['tag'] === 'input' || $this->_data['tag'] === 'button') {
			$output .= ' type="'.$this->_data['type'].'"';
		}
		if (isset($this->_data['id'])) {
			$output .= ' id="'.$this->_data['id'].'"';
		}
		if (isset($this->_data['name'])) {
			$output .= ' name="'.$this->_data['name'].'"';
		}
		if ($this->_data['tag'] === 'input' && $this->_data['type'] != 'file') {
			$output .= ' value="'.$this->_data['value'].'"';
		}
		$output .= ' class="'.$className.'"';
		switch ($this->_data['tag']) {
			case 'input':
				switch ($this->_data['type'])
				{					
					case 'file':
						$output .= ' />';
						if ($this->_data['type'] === 'file') {
							if (isset($this->_data['value'])) {
								$output .= '&nbsp;<img align="top" src="'.base_url().$this->_data['value'].'" width="30px" />';
								$output .= '&nbsp;<input type="checkbox" name="delete_image_'.$this->_data['name'].'" value="1"/> Delete Image';
							}
						}
						break;
					case 'checkbox':
					case 'radio':
						$output .= ' '.$this->_data['checked'].' />';
						break;
					default:
						$output .= ' />';
						break;
				}
				break;
			case 'textarea':
				$output .= '>';
				$output .= $this->_data['value'];
				$output .= '</'.$this->_data['tag'].'>';
				break;
			case 'button':
				switch ($this->_data['type'])
				{
					case 'linkbutton':
						$output .= ' onclick="window.location="'.$this->_data['href'].'"">';
						$output .= $this->_data['value'];
						$output .= '</'.$this->_data['tag'].'>';
					break;
					default:
						$output .= '>';
						$output .= $this->_data['value'];
						$output .= '</'.$this->_data['tag'].'>';
					break;
				}
				break;
			case 'select':
				switch ($this->_data['type'])
				{
					case 'combobox':
						$output .= '>';
						if (count($this->_data['options']) == 0 && count($this->_source['source']) == 0) 
						{
							$output .= '<option></option>';
						} 
						else 
						{
							if (count($this->_data['options']) > 0) {
								foreach ($this->_data['options'] as $label => $value) {
									$output .= '<option';
									if ($value == $this->_data['value']) {
										$output .= ' selected="selected"';
									}
									$output .= ' value="'.$value.'">';
									$output .= $label;
									$output .= '</option>';
								}
							}
							if (count($this->_source['source']) > 0) {
								foreach ($this->_source['source'] as $entity) {
									$output .= '<option';
									$value = $entity->getData($this->_source['option']['value']);
									if ($value == $this->_data['value']) {
										$output .= ' selected="selected"';
									}
									$output .= ' value="'.$entity->getData($this->_source['option']['value']).'">';
									$output .= $entity->getData($this->_source['option']['display']);
									$output .= '</option>';
								}
							}
						}
						break;
					case 'option':
						$output .= '>';
						if (count($this->_data['options']) == 0) {
							$output .= '<option></option>';
						} else {
							foreach ($this->_data['options'] as $label => $value) {
								$output .= '<option';
								if ($value == $this->_data['value']) {
									$output .= ' selected="selected"';
								}
								$output .= ' value="'.$value.'">';
								$output .= $label;
								$output .= '</option>';
							}
						}
						break;
				}
				$output .= '</'.$this->_data['tag'].'>';
				break;
			case 'span':
				if (in_array($this->_data['value'], $this->_data['options'])) {
					$output .= '>';
					foreach ($this->_data['options'] as $key => $value) {
						if ($this->_data['options'][$key] == $this->_data['value']) {
							$output .= $key;
						}
					}
					$output .= '</span>';
				}
				break;
		}
		return $output;
	}
}
/*
 * Test Unit
 * ///Button Submit
 * echo fx_control::newInstance('submit')->createType('submit')->setData('value', 'Save Category')->render();
 * ///Button Reset
 * echo fx_control::newInstance('reset')->createType('reset')->setData('value', 'Reset')->render();
 * ///Select
 * collection: collection of model, get by method `getCollection`
 * config_option_path: value_member/display_member
 * echo fx_control::newInstance('category_parent')->createType('combobox')
												  ->addOption('No Parent', 0)
												  ->binding($model, 'field_name', $collection, 'config_option_path')
												  ->render(); 
 * */